-
Notifications
You must be signed in to change notification settings - Fork 33
Improve linter UI test runners (and fix them on Windows!) #677
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
`ui_test` isn't allowed to find the host tuple itself, since it tries running `bevy_lint_driver -vV` and gets very confused when `bevy_lint_driver` silently eats the `-vV` flag because it expected `rustc`'s path instead. Because of that, we need to specify the host tuple with some default. Before, leaving it as an empty string worked fine, but in a future commit I'm going to introduce `DependencyBuilder`, which needs a valid host tuple. As such, the best solution is to properly query `rustc` for the host tuple and pass it to `ui_test`.
This makes `ui_test` build our dependencies in a separate crate, rather than expecting `bevy` to be built as a dev-dependency. This should hopefully fix #568 (comment), letting us run UI tests on Windows.
I ended up duplicating `host_tuple()`, but I personally am fine with it.
This lets us verify a specific exit code is set by `bevy_lint`, rather than just ignoring it completely.
Since `run_tests_generic()` doesn't parse arguments, I took the contents of `run_tests()` and inlined them here.
The linter's `assert!()` only works when the Rust compiler's diagnostics infra is setup.
This reverts commit 1a279ce.
| # Used to deserialize `--message-format=json` messages from Cargo. | ||
| serde_json = "1.0.145" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need serde_json anymore, as we're no longer deserializing JSON messages manually. ui_test handles that for us!
| # Used when running UI tests. | ||
| bevy = { version = "0.17.2", default-features = false, features = [ | ||
| "std", | ||
| # used for the `camera_modification_in_fixed_update` lint | ||
| "bevy_render", | ||
| ] } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This dependency has been moved to bevy_lint/tests/dependencies/Cargo.toml.
| name = "lint-ui-dependencies" | ||
| description = "A dummy crate that builds dependencies that `bevy_lint`'s UI tests need to import" | ||
| edition = "2024" | ||
| publish = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line is important: once we start cargo publish-ing the CLI and linter, this will prevent us from accidentally publishing this crate :)
| #![expect( | ||
| clippy::disallowed_macros, | ||
| reason = "`bevy_lint`'s macros are intended for lints, not tests" | ||
| )] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This #[expect(...)] is because we are using the standard library's assert!() macro. It's fine in this situation because we can't and shouldn't use the linter's version.
| # A dummy crate used to build dependencies that the linter needs for its UI tests. | ||
| "bevy_lint/tests/dependencies", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I figured it was easiest to add ui-lint-dependencies to the workspace; this way it shares the target directory for caching and Cargo.lock for dependency sharing.
On Windows if the first `cargo test` fails, it will not be caught as long as the second `cargo test` passes. It's super jank.
Sorry for the vague title! This PR is a refactor of our linter UI test runners (
ui.rsandui_cargo.rs) with a number of benefits:bevyand its dependencies withDependencyBuilder(fixes Fix CI on Windows #568 (comment), which prevented Fix CI on Windows #568 from being merged)@exit-code: CODEannotation for Cargo UI tests, used to ensure checks passcargo test --test ui_cargo -- --bless)Here's a few notes I have on specific changes / design decisions:
Removing
test_utilsThe
test_utilsmodule had two main features:Configthat bothui.rsandui_cargo.rscould use, avoiding unnecessary duplicationbevycrate so UI tests could import itWhen looking over the
base_config(), I realizedui.rsused all of the configuration without modification, whileui_cargo.rsessentially overwrote the entire thing. Because of that, I think it is much clearer to define eachConfigseparately, rather than trying to use a shared base when there is little overlap. I think it worked! Compare the before-and-after forui_cargo.rs:bevy_cli/bevy_lint/tests/ui_cargo.rs
Lines 18 to 51 in 569ec9e
bevy_cli/bevy_lint/tests/ui_cargo.rs
Lines 21 to 40 in d80936b
The second feature
test_utilsprovided was building and locatinglibbevy.rlib. Turns out we can replace that with...Using
DependencyBuilderui_testprovides aDependencyBuilderthat makes it easy to build dependencies used by UI tests.DependencyBuilderprovides a shift in how we manage dependencies:test_utilsDependencyBuilder[dev-dependencies]lint-ui-dependenciescratecargo testruns.rlibs located by parsingcargo build's JSON output (which was jank enough that I wrote a blog post about an issue I found with it, whose fix never landed because it was in #568).rlibs handled byui_testbevy_lint_driverwith--externand-Lui_testcargo::rustc-link-searchin build scripts, causingwindowsdependency to fail to compile on Windowscargo::rustc-link-search: oli-obk/ui_test#220bevy::ecsshould be imported rather thanbevy_ecsbevy::ecsshould be importedOverall, using
DependencyBuildermakes it so we can build and run UI tests on Windows while also making maintaining the UI tests easier. The only downside I've found was thatBevyManifestisn't able to find these dependencies, so it isn't able to deduce thatbevy::ecsandbevy::reflectshould be imported rather thanbevy_ecsandbevy_reflect. I hacked around it here, but the solution isn't amazing.Properly query host tuple
One of the oldest issues (it's there in #32!) I ran into when introducing the UI test harness was
ui_testtrying to auto-detect the host tuple by callingbevy_lint_driver -vV, which the linter driver skipped because it expectedbevy_lint_driver rustc -vVinstead. I hacked around the issue by setting the host to an empty stringSome(String::new()), butDependencyBuilderdoesn't like that because it tries passing the host tocargo buildand ends up runningcargo build --target=. Because there's no value for--target=, Cargo exits with an error.Because there was no avoiding it anymore, I chose to instead run
rustc --print=host-tupleto get the actual host tuple (which for me returnsaarch64-apple-darwin). I duplicated this solution to bothui.rsandui_cargo.rsrather than re-introducingtest_utils, but I'm not set on that decision.#@exit-statusin Cargo UI testsWe previously discarded the exit code of Cargo UI tests because fail tests returned exit code 101, which
ui_testmistakenly thought was a compiler ICE rather than a proper error. Instead of blanketly allowing all exit codes, I wrote a small annotation that lets us specify what the exit code of a specific test should be. Now all tests intended to fail should have this at the beginning:And all tests intending to pass should use the normal
#@check-pass:I couldn't figure out a way to reprogram
ui_testto accept 101 as the normal error code, so this is the best thing I came up with.Argument parsing in
ui_cargo.rsui_cargo.rsusesui_test::run_tests_generic()because it needs to configure the runner to work onCargo.tomlfiles, not*.rsfiles.run_tests_generic()does not do any argument parsing, however, meaning flags like--blesswere completely ignored.Since
--blessis super useful, I copied the argument parsing code fromrun_tests()toui_cargo.rs. Cool stuff!